package com.example.rabbitmq.config;

import com.example.rabbitmq.convert.CustomConverter;
import com.example.rabbitmq.pojo.TestPojo;
import com.rabbitmq.client.*;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.util.HashMap;


@Configuration
public class RabbitMQConfiguration {

//###########################################配置#######################################################

    @Bean
    public RabbitTemplate rabbitTemplate(org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate();
        template.setConnectionFactory(connectionFactory);
        //发布时的消息转换器
        template.setMessageConverter(new Jackson2JsonMessageConverter());
        return template;
    }

    /**
     *
     * 手动构建容器，处理消息
     * @param connectionFactory rabbitmq服务器连接工厂
     * @return
     */
    @Bean("customSimpleRabbitListenerContainerFactory")
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        //设置消息转换器，即消费者消费该消息时进行的消息转换器
        //自定义消息转换器，实现MessageConverter接口即可
        factory.setMessageConverter(new CustomConverter(TestPojo.class));
        return factory;
    }



//########################################################################################################
    //direct交换机
    public static final String DIRECT_EXCHANGE_NAME="direct_exchange";
    //direct交换机、无死信交换机、无备用队列
    public static final String DIRECT_EXCHANGE_NAME2="direct_exchange2";
    //延迟交换机
    public static final String DELAY_EXCHANGE_NAME="delay_exchange";

    //队列
    public static final String QUEUE_NAME="queue";
    public static final String ROUTING_KEY="routing_key";
    //死信交换机、死信队列、死信路由键
    public static final String DEAD_EXCHANGE_NAME="dead_exchange";
    public static final String DEAD_QUEUE_NAME="dead_queue";
    public static final String DEAD_ROUTING_KEY="dead_routing_key";

    //备用交换机,一般建议fanout类型
    public static final String BACKUP_EXCHANGE_NAME="backup_exchange";
    //一般备用交换机建议要有一个备用队列、一个警告队列
    public static final String WARN_QUEUE_NAME="warn_queue";
    public static final String BACKUP_QUEUE_NAME="backup_name";


    //声明一个交换机
    @Bean
    public DirectExchange directExchange(){
        //为directExchange交换机添加一个备用交换机
//        HashMap<String, Object> arguments = new HashMap<>();
//        arguments.put("alternate-exchange",BACKUP_EXCHANGE_NAME);
//        return new DirectExchange(DIRECT_EXCHANGE_NAME,false,false,arguments);
        return ExchangeBuilder.directExchange(DIRECT_EXCHANGE_NAME).durable(false).alternate(BACKUP_EXCHANGE_NAME).build();
    }
    //声明一个队列
    @Bean("queue")
    public Queue queueDeclare(){
        HashMap<String, Object> queueProperties = new HashMap<>();
        //该队列里的所有消息的过期时间为10s，建议在发布确认那里写TTL时间，这样灵活，可以任意时间
        //queueProperties.put("x-message-ttl",10000);
        //队列最多可以存放10条消息
        queueProperties.put("x-max-length",10);
        //drop-head/reject-publish/reject-publish-dlx
        //queueProperties.put("x-overflow",reject-publish);
        //队列在被自动删除之前可以使用30s,一旦设置，不管有没有设置自动删除，只要空闲30s后，自动删除
        queueProperties.put("x-expires",30000);
        //设置该队列有死信交换机和死信队列
        queueProperties.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
        //指定死信路由键前，先指定死信交换机，死信路由键不设置，则默认为"";
        queueProperties.put("x-dead-letter-routing-key",DEAD_ROUTING_KEY);
        queueProperties.put("x-queue-mode", "lazy");
        return new Queue(QUEUE_NAME,true,false,false,queueProperties);
    }
    //将队列绑定到交换机中
    @Bean
    public Binding queueBindToDirectExchange(Queue queue,DirectExchange directExchange){
        //注意：不同的交换机，to之后返回的可能不同。比如：to(FanoutExchange)返回的是binding对象，而to(DirectExchange)返回DirectExchangeRoutingKeyConfigurer对象
        return BindingBuilder.bind(queue).to(directExchange).with(ROUTING_KEY);
    }

    @Bean
    public DirectExchange simpleExchange(){
        return new DirectExchange(DIRECT_EXCHANGE_NAME2,false,false,null);
    }
    @Bean
    public Binding queueBindToNothingExchange(Queue queue,DirectExchange simpleExchange){
        //to之后返回binding对象，自己看源码
        return BindingBuilder.bind(queue).to(simpleExchange).with(ROUTING_KEY);
    }


    //声明一个死信交换机
    @Bean
    public DirectExchange deadExchange(){
        return new DirectExchange(DEAD_EXCHANGE_NAME,false,false,null);
    }
    //声明一个死信队列
    @Bean
    public Queue deadQueue(){
        return new Queue(DEAD_QUEUE_NAME,false,false,true,null);
    }
    //将死信队列和死信交换机绑定起来，用死信交换机键DEAD_ROUTING_KEY
    @Bean
    public Binding deadQueueBindToDeadExchange(Queue deadQueue,DirectExchange deadExchange){
        return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTING_KEY);
    }



    //基于插件的延迟交换机
    @Bean("delayExchange")
    public CustomExchange delayExchange(){
        HashMap<String, Object> delayExchangeProperties= new HashMap<>();
        //指定延迟交换机的交换机类型
        delayExchangeProperties.put("x-delayed-type",BuiltinExchangeType.DIRECT.getType());
        //由于延迟交换机类型，是插件的，所以声明时使用自定义交换机类型
        return new CustomExchange(DELAY_EXCHANGE_NAME, "x-delayed-message",false,false,delayExchangeProperties);
    }
    //将延迟交换机绑定到queue队列中，键为routing_key
    @Bean
    public Binding queueBindToDelayExchange(Queue queue,CustomExchange delayExchange){
        //自定义交换机类型，绑定时，如果带参数，则使用and，如果不带参数使用noargs
        return BindingBuilder.bind(queue).to(delayExchange).with(ROUTING_KEY).noargs();
    }




    //创建一个交换机作为备用交换机
    @Bean
    public FanoutExchange backupExchange(){
        return new FanoutExchange(BACKUP_EXCHANGE_NAME,true,false,null);
    }
    //备用队列
    @Bean
    public Queue backupQueue(){
        return new Queue(BACKUP_QUEUE_NAME,false,false,false,null);
    }
    //备用队列绑定到备用交换机
    @Bean
    public Binding backupQueueBindToBackupExchange(Queue backupQueue,FanoutExchange backupExchange){
        return BindingBuilder.bind(backupQueue).to(backupExchange);
    }
    //警告队列
    @Bean
    public Queue warnQueue(){
        return new Queue(WARN_QUEUE_NAME,false,false,false,null);
    }
    //警告队列绑定到备用交换机
    @Bean
    public Binding warnQueueBindToBackupExchange(Queue warnQueue,FanoutExchange backupExchange){
        return BindingBuilder.bind(warnQueue).to(backupExchange);
    }






//#####################################原始#############################################//
    /**
     * 原始简单设置
     * @return
     */
    @Bean
    public ConnectionFactory createRabbitMQConnection() throws Exception{
        //创建rabbitmq的连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        //factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");
        return  factory;
    }

}
